<?php

/**
 * ValidatorBuilder builds and assigns complex validators.
 *
 * @package    carga_lectiva
 * @subpackage validator
 */
class ValidatorBuilder
{
  protected
    $types           = array(),
    $validatorSchema = null,
    $labels          = array();
    
  protected static
    $msgEmpty         = 'El campo \'%field%\' no puede tener espacios en blanco.',
    $msgEmptyList     = 'Por favor, seleccione  una opcion del campo \'%field%\'.',
    $msgLong          = 'El campo  \'%field%\' es demasiado largo (%max_length% caracteres como maximo).',
    $msgShort         = 'El campo \'%field%\' es demasiado corto (%min_length% caracteres como minimo).',
    $msgCombo         = 'Por favor, selecciona una opcion del campo \'%field%\'.',
    $msgComboInvalid  = 'El campo \'%field%\' tiene un error en la opcion seleccionada.',
    $msgRegex         = 'El campo \'%field%\' tiene caracteres prohibidos.',
    $msgUrl           = 'Por favor, Escriba una Url correcta en el campo \'%field%\'.',
    $msgEmail         = 'Por favor, escriba correctamente un e-mail en el campo \'%field%\'.',
    $msgDate          = 'Por favor, seleccione una fecha correcta en el campo \'%field%\'.',
    $msgMin           = 'El campo \'%field%\' debe ser mayot o igual que %min%.',
    $msgMax           = 'El \'%field%\' debe ser menir o igual que %max%.',
    $msgLength        = 'El campo \'%field%\' debe tener como minimo %length% caracteres.',
    $msgCaptcha       = 'El campo  \'%field%\' comtiene un codigo mal escrito.',
    
    $msgMaxSize       = 'El archivo en el campo \'%field%\' es demasiado pesado (maximo: %max_size% bytes).',
    $msgMimeTypes     = 'El archivo en el campo \'%field%\' tiene un tipo mime invalido (%mime_type%).',
    $msgPartialFile   = 'El archivo en el campo \'%field%\' fue levantado parcialmente.',
    $msgNoTmpDir      = 'El archivo en el campo \'%field%\' a perdido su carpeta temporalmente.',
    $msgCantWrite     = 'El archivo en el campo \'%field%\' puede no estar escrito en el disco.',
    $msgFileExtension = 'El archivo en el campo \'%field%\' fue detenido por la extension.',
    
    $reAlphabet       = '/^[A-Za-z Ã¡Ã©Ã­Ã³ÃºÃ�Ã‰Ã�Ã“ÃšÃ±Ã‘,\.\'"_:\* \\\ \/ # ]+$/',
    $reAlphabetExt    = '/^[\w Ã¡Ã©Ã­Ã³ÃºÃ�Ã‰Ã�Ã“ÃšÃ±Ã‘\.,\-_:?Â¿ %\$\n\r\+ @\'"\* \\\ \/ # ]+$/',
    $reNumber         = '/^\d+$/',
    $reWikiText       = '/^[^Æ’]+$/',
    $rePassword       = '/^[^\n]+$/',
    $reAlphaNumerical = '/^[\w]+$/',
    $reUser           = '/^[\w.\-_]+$/',
    $rePhone          = '/^[\(\)\d \-\* \\\ \/ # ]+$/',
    $reCode           = '/^[A-Za-z0-9\-\_]+$/',
    $reToken          = '/^[a-zA-Z0-9]+$/';
	
  public function __construct($types, sfValidatorSchema $validatorSchema, $labels)
  {
  	$this->types           = $types;
  	$this->validatorSchema = $validatorSchema;
  	$this->labels          = $labels;
  }
  
  public function build()
  {
    foreach ($this->types as $field => $type)
    {
      if ($type == '=')
      {
      }
      elseif ($type == '-')
      {
      	unset($this->validatorSchema[$field]);
      }
      else
      {
      	$options = array();
      	if (is_array($type))
      	{
      	  $options = $type[1];
      	  $type    = $type[0];
      	}
      	
      	$setType = 'setType'.sfInflector::camelize($type);
      	$this->$setType($field, $options);
      }
    }
    
    $this->buildPostValidators($this->validatorSchema->getPostValidator());

    return $this->validatorSchema;
  }
  
  
  protected function setTypeCaptcha($field)
  {
  	$validator = $this->validatorSchema[$field];
  	
  	$validator->addMessage('max_length', $this->getMessage($field, self::$msgLong));
  	$validator->addMessage('min_length', $this->getMessage($field, self::$msgShort));
  	
  	$validator = new sfValidatorAnd
  	             (
  	               array
  	               (
  	                 $validator,
  	                 new kcValidatorCaptcha
  	                 (
  	                   array('length' => sfConfig::get('app_captcha_length', 5), 'required' => true), 
  	                   array
  	                   (
  	                     'length'  => $this->getMessage($field, self::$msgLength), 
  	                     'captcha' => $this->getMessage($field, self::$msgCaptcha),
  	                   )
  	                 )
  	               ),
  	               
  	               array('required' => $validator->getOption('required'), 'trim' => true),
  	               array('required' => $this->getMessage($field, self::$msgEmpty))
  	             );
  	             
    $this->validatorSchema[$field] = $validator;
  }
  
  
  protected function setTypeCode($field)
  {
  	$validator = $this->validatorSchema[$field];
  	
  	$validator->addMessage('max_length', $this->getMessage($field, self::$msgLong));
  	$validator->addMessage('min_length', $this->getMessage($field, self::$msgShort));
  	
  	$validator = new sfValidatorAnd
  	             (
  	               array
  	               (
  	                 $validator,
  	                 new sfValidatorRegex
  	                 (
  	                   array('pattern' => self::$reCode),
  	                   array('invalid' => $this->getMessage($field, self::$msgRegex))
  	                 )
  	               ),
  	               
  	               array('required' => $validator->getOption('required'), 'trim' => true),
  	               array('required' => $this->getMessage($field, self::$msgEmpty))
  	             );
  	             
    $this->validatorSchema[$field] = $validator;
  }
  
  protected function setTypeName($field)
  {
  	$validator = $this->validatorSchema[$field];
  	
  	$validator->addMessage('max_length', $this->getMessage($field, self::$msgLong));
  	$validator->addMessage('min_length', $this->getMessage($field, self::$msgShort));
  	
  	$validator = new sfValidatorAnd
  	             (
  	               array
  	               (
  	                 $validator,
  	                 new sfValidatorRegex
  	                 (
  	                   array('pattern' => self::$reAlphabet),
  	                   array('invalid' => $this->getMessage($field, self::$msgRegex))
  	                 )
  	               ),
  	               
  	               array('required' => $validator->getOption('required'), 'trim' => true),
  	               array('required' => $this->getMessage($field, self::$msgEmpty))
  	             );
  	             
    $this->validatorSchema[$field] = $validator;
  }
  protected function setTypeNameUrl($field)
  {
  	$validator = $this->validatorSchema[$field];
  	
  	$validator->setOption('required', false);
  }
  protected function setTypeText($field)
  {
  	$validator = $this->validatorSchema[$field];
  	
  	$validator->addMessage('max_length', $this->getMessage($field, self::$msgLong));
  	$validator->addMessage('min_length', $this->getMessage($field, self::$msgShort));
  	
  	$validator = new sfValidatorAnd
  	             (
  	               array
  	               (
  	                 $validator,
  	                 new sfValidatorRegex
  	                 (
  	                   array('pattern' => self::$reAlphabetExt),
  	                   array('invalid' => $this->getMessage($field, self::$msgRegex))
  	                 )
  	               ),
  	               
  	               array('required' => $validator->getOption('required'), 'trim' => true),
  	               array('required' => $this->getMessage($field, self::$msgEmpty))
  	             );
  	             
  	$this->validatorSchema[$field] = $validator;
  }
  protected function setTypeNumberFixed($field)
  {
  	$validator = $this->validatorSchema[$field];
  	
  	$validator->addMessage('max_length', $this->getMessage($field, self::$msgLong));
  	$validator->addMessage('min_length', $this->getMessage($field, self::$msgShort));
  	
  	$validator = new sfValidatorAnd
  	             (
  	               array
  	               (
  	                 $validator,
  	                 new sfValidatorRegex
  	                 (
  	                   array('pattern' => self::$reNumber),
  	                   array('invalid' => $this->getMessage($field, self::$msgRegex))
  	                 )
  	               ),
  	               
  	               array('required' => $validator->getOption('required'), 'trim' => true),
  	               array('required' => $this->getMessage($field, self::$msgEmpty))
  	             );
  	             
  	$this->validatorSchema[$field] = $validator;
  }
  protected function setTypeWikiText($field)
  {
  	$validator = $this->validatorSchema[$field];
  	
  	$validator->addMessage('max_length', $this->getMessage($field, self::$msgLong));
  	$validator->addMessage('min_length', $this->getMessage($field, self::$msgShort));
  	
  	$validator = new sfValidatorAnd
  	             (
  	               array
  	               (
  	                 $validator,
  	                 new sfValidatorRegex
  	                 (
  	                   array('pattern' => self::$reWikiText),
  	                   array('invalid' => $this->getMessage($field, self::$msgRegex))
  	                 )
  	               ),
  	               
  	               array('required' => $validator->getOption('required'), 'trim' => true),
  	               array('required' => $this->getMessage($field, self::$msgEmpty))
  	             );
  	             
  	$this->validatorSchema[$field] = $validator;
  }
  
  protected function setTypeUser($field)
  {
  	$validator = $this->validatorSchema[$field];
  	
  	$validator->addMessage('max_length', $this->getMessage($field, self::$msgLong));
  	$validator->addMessage('min_length', $this->getMessage($field, self::$msgShort));
  	
  	$validator = new sfValidatorAnd
  	             (
  	               array
  	               (
  	                 $validator,
  	                 new sfValidatorRegex
  	                 (
  	                   array('pattern' => self::$reUser),
  	                   array('invalid' => $this->getMessage($field, self::$msgRegex))
  	                 )
  	               ),
  	               
  	               array('required' => $validator->getOption('required'), 'trim' => true),
  	               array('required' => $this->getMessage($field, self::$msgEmpty))
  	             );
  	             
  	$this->validatorSchema[$field] = $validator;
  }
  protected function setTypeToken($field)
  {
  	$validator = $this->validatorSchema[$field];
  	
  	$validator->addMessage('max_length', $this->getMessage($field, self::$msgLong));
  	$validator->addMessage('min_length', $this->getMessage($field, self::$msgShort));
  	
  	$validator = new sfValidatorAnd
  	             (
  	               array
  	               (
  	                 $validator,
  	                 new sfValidatorRegex
  	                 (
  	                   array('pattern' => self::$reToken),
  	                   array('invalid' => $this->getMessage($field, self::$msgRegex))
  	                 )
  	               ),
  	               
  	               array('required' => $validator->getOption('required'), 'trim' => true),
  	               array('required' => $this->getMessage($field, self::$msgEmpty))
  	             );
  	             
  	$this->validatorSchema[$field] = $validator;
  }
  protected function setTypePassword($field)
  {
  	$validator = $this->validatorSchema[$field];
  	$validator->setMessage('max_length', $this->getMessage($field, self::$msgLong));
  	$validator->setMessage('min_length', $this->getMessage($field, self::$msgShort));
  	$validator->setOption('min_length', 1);
  	$validator->setOption('max_length', 15);
  	
  	$validator = new sfValidatorAnd
  	             (
  	               array
  	               (
  	                 $validator,
  	                 new sfValidatorRegex
  	                 (
  	                   array('pattern' => self::$rePassword),
  	                   array('invalid' => $this->getMessage($field, self::$msgRegex))
  	                 )
  	               ),
  	               
  	               array('required' => $validator->getOption('required'), 'trim' => false),
  	               array('required' => $this->getMessage($field, self::$msgEmpty))
  	             );
  	             
    $this->validatorSchema[$field] = $validator;
  }
  
  protected function setTypeUrl($field)
  {
  	$validator = $this->validatorSchema[$field];
  	
  	$validator->addMessage('max_length', $this->getMessage($field, self::$msgLong));
  	$validator->addMessage('min_length', $this->getMessage($field, self::$msgShort));
  	
  	$validator = new sfValidatorAnd
  	             (
  	               array
  	               (
  	                 $validator,
  	                 new sfValidatorUrl
  	                 (
  	                   array(),
  	                   array('invalid' => $this->getMessage($field, self::$msgUrl))
  	                 )
  	               ),
  	               
  	               array('required' => $validator->getOption('required'), 'trim' => true),
  	               array('required' => $this->getMessage($field, self::$msgEmpty))
  	             );
  	             
  	$this->validatorSchema[$field] = $validator;
  }
  protected function setTypeUrlWeb($field)
  {
  	$validator = $this->validatorSchema[$field];
  	
  	$validator->addMessage('max_length', $this->getMessage($field, self::$msgLong));
  	$validator->addMessage('min_length', $this->getMessage($field, self::$msgShort));
  	
  	$validator = new sfValidatorAnd
  	             (
  	               array
  	               (
  	                 $validator,
  	                 new sfValidatorUrlWeb
  	                 (
  	                   array(),
  	                   array('invalid' => $this->getMessage($field, self::$msgUrl))
  	                 )
  	               ),
  	               
  	               array('required' => $validator->getOption('required'), 'trim' => true),
  	               array('required' => $this->getMessage($field, self::$msgEmpty))
  	             );
  	             
  	$this->validatorSchema[$field] = $validator;
  }
  protected function setTypeEmail($field)
  {
  	$validator = $this->validatorSchema[$field];
  	
  	$validator->addMessage('max_length', $this->getMessage($field, self::$msgLong));
  	$validator->addMessage('min_length', $this->getMessage($field, self::$msgShort));
  	
  	$validator = new sfValidatorAnd
  	             (
  	               array
  	               (
  	                 $validator,
  	                 new sfValidatorEmail
  	                 (
  	                   array(),
  	                   array('invalid' => $this->getMessage($field, self::$msgEmail))
  	                 )
  	               ),
  	               
  	               array('required' => $validator->getOption('required'), 'trim' => true),
  	               array('required' => $this->getMessage($field, self::$msgEmpty))
  	             );
  	             
  	$this->validatorSchema[$field] = $validator;
  }
  
  protected function setTypePhone($field)
  {
  	$validator = $this->validatorSchema[$field];
  	
  	$validator->addMessage('max_length', $this->getMessage($field, self::$msgLong));
  	$validator->addMessage('min_length', $this->getMessage($field, self::$msgShort));
  	
  	$validator = new sfValidatorAnd
  	             (
  	               array
  	               (
  	                 $validator,
  	                 new sfValidatorRegex
  	                 (
  	                   array('pattern' => self::$rePhone),
  	                   array('invalid' => $this->getMessage($field, self::$msgRegex))
  	                 )
  	               ),
  	               
  	               array('required' => $validator->getOption('required'), 'trim' => true),
  	               array('required' => $this->getMessage($field, self::$msgEmpty))
  	             );
  	             
  	$this->validatorSchema[$field] = $validator;
  }
  protected function setTypeCombo($field, $options)
  {
  	$validator = $this->validatorSchema[$field];
  	
  	if ($validator instanceof sfValidatorDoctrineChoice)
  	{
  	  $validator->setMessage('required', $this->getMessage($field, self::$msgCombo));
  	  $validator->setMessage('invalid', $this->getMessage($field, self::$msgCombo));
  	  return;
  	}
  	
  	$validator = new sfValidatorChoice
  	             (
  	               array
  	               (
  	                 'choices'  => $options['choices'],
  	                 'required' => $validator->getOption('required')
  	               ),
  	               array
  	               (
  	                 'required' => $this->getMessage($field, self::$msgCombo),
  	                 'invalid'  => $this->getMessage($field, self::$msgComboInvalid)
  	               )
  	             );
  	
  	$this->validatorSchema[$field] = $validator;
  }
  
  protected function setTypeInteger($field, $options)
  {
  	$validator = $this->validatorSchema[$field];

  	$validator = new sfValidatorInteger
  	             (
  	               array
  	               (
  	                 'required' => $validator->getOption('required'),
  	                 'trim'     => true,
  	               ),
  	               array
  	               (
  	                 'required' => $this->getMessage($field, self::$msgEmpty),
  	                 'invalid'  => $this->getMessage($field, self::$msgRegex),
  	                 'min'      => $this->getMessage($field, self::$msgMin),
  	                 'max'      => $this->getMessage($field, self::$msgMax)
  	               )
  	             );
    
  	if (isset($options['min']))
  	{
  	  $validator->setOption('min', $options['min']);
  	}
  	if (isset($options['max']))
  	{
  	  $validator->setOption('max', $options['max']);
  	}
  	
    $this->validatorSchema[$field] = $validator;
  }
  protected function setTypeFloat($field, $options)
  {
  	$validator = $this->validatorSchema[$field];
  	
  	$validator = new sfValidatorNumber
  	             (
  	               array
  	               (
  	                 'required' => $validator->getOption('required'),
  	                 'trim'     => true,
  	               ),
  	               array
  	               (
  	                 'required' => $this->getMessage($field, self::$msgEmpty),
  	                 'invalid'  => $this->getMessage($field, self::$msgRegex),
  	                 'min'      => $this->getMessage($field, self::$msgMin),
  	                 'max'      => $this->getMessage($field, self::$msgMax)
  	               )
  	             );
    
  	if (isset($options['min']))
  	{
  	  $validator->setOption('min', $options['min']);
  	}
  	if (isset($options['max']))
  	{
  	  $validator->setOption('max', $options['max']);
  	}
  	
    $this->validatorSchema[$field] = $validator;
  }
  
  protected function setTypeDate($field, $options)
  {
  	$validator = $this->validatorSchema[$field];
  	
  	$validator->setMessage('required', $this->getMessage($field, self::$msgEmpty));
  	$validator->setMessage('invalid' , $this->getMessage($field, self::$msgDate));
  	
  	if (isset($options['min']))
  	{
  	  $validator->setOption('min', $options['min']);
  	  $validator->setMessage('min', $this->getMessage($field, $validator->getMessage('min')));
  	}
  	if (isset($options['max']))
  	{
  	  $validator->setOption('max', $options['max']);
  	  $validator->setMessage('max', $this->getMessage($field, $validator->getMessage('max')));
  	}
  	
    $this->validatorSchema[$field] = $validator;
  }
  protected function setTypeList($field)
  {
    $validator = $this->validatorSchema[$field];
    
    $validator->setMessage('required', $this->getMessage($field, self::$msgEmptyList));
    
    $this->validatorSchema[$field] = $validator;
  }
  
  protected function setTypePass($field, $options)
  {
  	$validator = new sfValidatorPass(array('required' => false));
  	
    $this->validatorSchema[$field] = $validator;
  }
  protected function setTypeDateTime()
  {
  }
  protected function setTypeFile($field, $options)
  {
  	$validator = $this->validatorSchema[$field];
  	
  	$validator->setMessage('required', $this->getMessage($field, self::$msgEmpty));
  	
  	$validator->setMessage('max_size'  , $this->getMessage($field, self::$msgMaxSize));
  	$validator->setMessage('mime_types', $this->getMessage($field, self::$msgMimeTypes));
  	$validator->setMessage('partial'   , $this->getMessage($field, self::$msgPartialFile));
  	$validator->setMessage('no_tmp_dir', $this->getMessage($field, self::$msgNoTmpDir));
  	$validator->setMessage('cant_write', $this->getMessage($field, self::$msgCantWrite));
  	$validator->setMessage('extension' , $this->getMessage($field, self::$msgFileExtension));
  	
    $this->validatorSchema[$field] = $validator;
  }
  
  protected function buildPostValidators($validator)
  {
  	if ($validator instanceof sfValidatorAnd || $validator instanceof sfValidatorOr)
  	{
  	  return $this->buildPostValidators($validator->getValidators());
  	}
  	
  	if (is_array($validator))
  	{
  	  foreach ($validator as $val)
  	  {
  	  	$this->buildPostValidators($val);
  	  }
  	  
  	  return;
  	}
  	
  	if ($validator instanceof sfValidatorDoctrineUnique)
  	{
  	  $column = $validator->getOption('column');
  	  if (is_array($column))
  	  {
  	  	$column = $this->getLabelFields($column);
  	  	$fields = implode(", ", $column);
  	  }
  	  else
  	  {
  	  	$fields = $this->labels[$column];
  	  }
  	  
      $validator->setMessage('invalid', sprintf('A record with the same "%s" already exist.', $fields));
      
      return;
  	}
  	
  	if ($validator instanceof LoginValidator)
  	{
  	  $column = $validator->getOption('column');
  	  if (is_array($column))
  	  {
  	  	$column = $this->getLabelFields($column);
  	  	$fields = implode(", ", $column);
  	  }
  	  else
  	  {
  	  	$fields = $this->labels[$column];
  	  }
  	  
      $validator->setMessage('invalid', sprintf('"%s" incorrect.', $fields));
      
      return;
  	}
  	
  	if ($validator instanceof sfValidatorSchemaCompare)
  	{
  	  $keys = array_map(create_function('$v', 'return \'%\'.$v.\'%\'; '), array_keys($this->labels));
      $validator->setMessage('invalid', str_replace($keys, $this->labels, $validator->getMessage('invalid')));
      
      return;
  	}
  }
  
  protected function getMessage($field, $msg)
  {
  	return str_replace('%field%', $this->labels[$field], $msg);
  }
  protected function getLabelFields($fields)
  {
  	$labels = array();
  	foreach ($fields as $field)
  	{
  	  if (isset($this->labels[$field]))
  	  {
  	    $labels[] = $this->labels[$field];
  	  }
  	  else
  	  {
  	  	$labels[] = $field;
  	  }
  	}
  	
  	return $labels;
  }
}
    